#include "RoceSenderManager.h"
#include <iostream>
#include <unistd.h>

namespace ai_sim {

RoceSenderManager::RoceSenderManager(int mss) 
{
  sendMss = mss;
  sendNext = 0;
  sendUna = 0;
  flows.clear();
}


SegmentInfo* RoceSenderManager::getNextSegment() {
  int i = 0;
  for (; i < flows.size(); ++i) {
    if (flows[i].startSeqNum > sendNext) {
      break;
    }
  }
  const FlowInfo& flow_info = flows.at(i - 1);
  uint32_t last_seq_num = flow_info.startSeqNum + (flow_info.flowSize + sendMss - 1 ) / sendMss;
  if(sendNext < last_seq_num) {
    bool is_last = false;
    int seg_size = sendMss;
    if (sendNext + 1 == last_seq_num) {
      is_last = true;
      if (flow_info.flowSize % sendMss > 0) {
        seg_size = flow_info.flowSize % sendMss;
      }
    }
    SegmentInfo* segment_info = new SegmentInfo(flow_info.flow, is_last, sendNext, seg_size);
    ++sendNext;
    return segment_info;
  }
  else
    return nullptr;
}

void RoceSenderManager::putLargeChunk(const ai_sim::Flow& flow) {
  if (flows.empty()) {
    flows.emplace_back(flow, sendNext);
  } else {
    uint32_t start_seq_num = (flows.back().flowSize + sendMss - 1 ) / sendMss + flows.back().startSeqNum;
    flows.emplace_back(flow, start_seq_num);
  }
}

void RoceSenderManager::handleAck(uint32_t seqNum) {
  sendUna = seqNum;
  if (sendNext < sendUna) {
    sendNext = sendUna;
  }
  doClear();
}

void RoceSenderManager::handleNack(uint32_t seqNum) {
  //std::cout<<"["<<sendNext<<","<<seqNum<<"]"<<endl;
  if (seqNum < sendUna) {
    throw "outdated nack";
  }
  sendNext = seqNum;
}

bool RoceSenderManager::isSendCompleted() {
  return flows.empty();
}

void RoceSenderManager::doClear() {
  int finished_flow_indx = 0;
  for (; finished_flow_indx < flows.size(); ++finished_flow_indx) {
    if (sendUna < (flows[finished_flow_indx].flowSize + sendMss - 1 ) / sendMss + flows[finished_flow_indx].startSeqNum) {
      break;
    }
  }
  for (int i = finished_flow_indx - 1; i >= 0; i--) {
    flows.erase(flows.begin() + i);
  }
}

}